home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / mmu / MuForce / Contributions / Sashimi / Source / sashimi.c < prev    next >
C/C++ Source or Header  |  2002-03-12  |  28KB  |  1,199 lines

  1. /*
  2.  * $Id: sashimi.c 1.9 1999/06/20 10:22:23 olsen Exp olsen $
  3.  *
  4.  * Sashimi -- intercepts raw serial debugging output on your own machine
  5.  *
  6.  * Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  7.  * Public Domain
  8.  *
  9.  * :ts=4
  10.  */
  11.  
  12. /****************************************************************************/
  13.  
  14. #define NULL ((APTR)0UL)
  15.  
  16. /****************************************************************************/
  17.  
  18. #include <exec/execbase.h>
  19. #include <exec/memory.h>
  20.  
  21. #include <devices/timer.h>
  22.  
  23. #include <dos/dosextens.h>
  24. #include <dos/rdargs.h>
  25.  
  26. #include <clib/timer_protos.h>
  27. #include <clib/exec_protos.h>
  28. #include <clib/dos_protos.h>
  29.  
  30. #include <pragmas/timer_pragmas.h>
  31. #include <pragmas/exec_sysbase_pragmas.h>
  32. #include <pragmas/dos_pragmas.h>
  33.  
  34. #define USE_BUILTIN_MATH
  35. #include <string.h>
  36. #include <stddef.h>
  37. #include <stdio.h>
  38.  
  39. /****************************************************************************/
  40.  
  41. STRPTR Version = "$VER: Sashimi 1.6 (20.6.99)\r\n";
  42.  
  43. /****************************************************************************/
  44.  
  45. #define OK        (0)
  46. #define NOT        !
  47. #define BUSY    NULL
  48. #define ZERO    ((BPTR)0UL)
  49.  
  50. /****************************************************************************/
  51.  
  52. enum
  53. {
  54.     MODE_Regular,
  55.     MODE_Recovery
  56. };
  57.  
  58. /****************************************************************************/
  59.  
  60. #define MILLION 1000000
  61.  
  62. /****************************************************************************/
  63.  
  64. STATIC struct Device * TimerBase;
  65.  
  66. /****************************************************************************/
  67.  
  68. extern struct Library * SysBase;
  69. extern struct Library * DOSBase;
  70.  
  71. /****************************************************************************/
  72.  
  73. typedef LONG    SWITCH;
  74. typedef LONG *    NUMBER;
  75. typedef STRPTR    KEY;
  76.  
  77. STATIC struct
  78. {
  79.     /* Startup options */
  80.     KEY        Recover;    /* Recover any old Sashimi buffer still in memory */
  81.     SWITCH    On;            /* Ignored */
  82.     NUMBER    BufferK;    /* Buffer size, to the power of two */
  83.     NUMBER    BufferSize;    /* Buffer size in bytes */
  84.     SWITCH    NoPrompt;    /* Do not show the initial prompt message */
  85.     SWITCH    Quiet;        /* Do not produce any output at all */
  86.     SWITCH    AskExit;    /* Ask whether to exit the program */
  87.     SWITCH    AskSave;    /* Ask for a file to save the buffer to when exiting */
  88.     SWITCH    TimerOn;    /* Check the circular buffer every 1/10 of a second */
  89.     SWITCH    Console;    /* Open a console window for I/O */
  90.     KEY        Window;        /* Console window specifier */
  91.  
  92.     /* Runtime options */
  93.     SWITCH    Off;        /* Turn Sashimi off */
  94.     SWITCH    Save;        /* Save the circular buffer contents */
  95.     KEY        SaveAs;        /* Save the circular buffer contents under a specific name */
  96.     SWITCH    Empty;        /* Empty the circular buffer */
  97. } ShellArguments;
  98.  
  99. STATIC const STRPTR ShellTemplate =
  100.     "RECOVER/K,"
  101.     "ON/S,"
  102.     "BUFK/N,"
  103.     "BUFFERSIZE/N,"
  104.     "NOPROMPT/S,"
  105.     "QUIET/S,"
  106.     "ASKEXIT/S,"
  107.     "ASKSAVE/S,"
  108.     "TIMERON/S,"
  109.     "CONSOLE/S,"
  110.     "WINDOW/K,"
  111.     "OFF/S,"
  112.     "SAVE/S,"
  113.     "SAVEAS/K,"
  114.     "EMPTY/S";
  115.  
  116. /****************************************************************************/
  117.  
  118. /* Eat me */
  119. #define COOKIE 0x08021999
  120.  
  121. struct SashimiResource
  122. {
  123.     struct Library    sr_Library;            /* Global link */
  124.     UWORD            sr_Pad;                /* Long word alignment */
  125.  
  126.     ULONG            sr_Cookie;            /* Magic marker */
  127.     APTR            sr_PointsToCookie;    /* Points back to cookie */
  128.     ULONG            sr_CreatedWhen;        /* When exactly was this data structure created? */
  129.  
  130.     struct Task *    sr_Owner;            /* Current owner of the patches */
  131.     LONG            sr_OwnerSigBit;
  132.     ULONG            sr_OwnerSigMask;    /* Signal mask to send when a new line is in the buffer. */
  133.  
  134.     ULONG            sr_FIFOTotalSize;    /* Number of bytes allocated for the buffer */
  135.     ULONG            sr_FIFOReadIndex;    /* Read index counter */
  136.     ULONG            sr_FIFOWriteIndex;    /* Write index counter */
  137.     ULONG            sr_FIFOBytesStored;    /* Number of bytes in the FIFO */
  138.     BOOL            sr_FIFOOverrun;        /* TRUE if the write index counter has
  139.                                          * overrun the read index counter.
  140.                                          */
  141.     BOOL            sr_FIFOWrapped;        /* TRUE if the write index counter has
  142.                                          * wrapped around the circular buffer.
  143.                                          */
  144.     UBYTE            sr_FIFO[1];            /* The message buffer */
  145. };
  146.  
  147. STATIC const STRPTR SashimiResourceName = "sashimi.resource";
  148. STATIC struct SashimiResource * GlobalSashimiResource;
  149.  
  150. /****************************************************************************/
  151.  
  152. extern LONG __far LVORawIOInit;
  153. extern LONG __far LVORawMayGetChar;
  154. extern LONG __far LVORawPutChar;
  155.  
  156. /****************************************************************************/
  157.  
  158. STATIC APTR OldRawIOInit;
  159. STATIC APTR OldRawMayGetChar;
  160. STATIC APTR OldRawPutChar;
  161.  
  162. /****************************************************************************/
  163.  
  164. VOID __saveds __asm
  165. NewRawIOInit(VOID)
  166. {
  167.     /* Nothing happens here */
  168. }
  169.  
  170. LONG __saveds __asm
  171. NewRawMayGetChar(VOID)
  172. {
  173.     /* We always return sort of a confirmation. */
  174.     return('y');
  175. }
  176.  
  177. /****************************************************************************/
  178.  
  179. STATIC LONG
  180. GetCharsInFIFO(struct SashimiResource * sr)
  181. {
  182.     LONG result;
  183.  
  184.     Disable();
  185.  
  186.     if(sr->sr_FIFOWrapped)
  187.         result = sr->sr_FIFOTotalSize;
  188.     else
  189.         result = sr->sr_FIFOWriteIndex;
  190.  
  191.     Enable();
  192.  
  193.     return(result);
  194. }
  195.  
  196. STATIC VOID
  197. EmptyFIFO(struct SashimiResource * sr)
  198. {
  199.     Disable();
  200.  
  201.     sr->sr_FIFOReadIndex    = 0;
  202.     sr->sr_FIFOWriteIndex    = 0;
  203.     sr->sr_FIFOBytesStored    = 0;
  204.     sr->sr_FIFOOverrun        = FALSE;
  205.     sr->sr_FIFOWrapped        = FALSE;
  206.  
  207.     Enable();
  208. }
  209.  
  210. STATIC LONG
  211. ReadFIFOChars(struct SashimiResource * sr,UBYTE * buffer,LONG maxChars)
  212. {
  213.     LONG result = 0;
  214.  
  215.     Disable();
  216.  
  217.     if(sr->sr_FIFOBytesStored > 0)
  218.     {
  219.         LONG howMany;
  220.  
  221.         if(maxChars > sr->sr_FIFOBytesStored)
  222.             maxChars = sr->sr_FIFOBytesStored;
  223.  
  224.         do
  225.         {
  226.             /* Find out how many characters can be read
  227.              * from the FIFO without overrunning the
  228.              * end of it. We don't read more than these
  229.              * few characters in one go.
  230.              */
  231.             howMany = min(maxChars,sr->sr_FIFOTotalSize - sr->sr_FIFOReadIndex);
  232.  
  233.             memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOReadIndex],howMany);
  234.  
  235.             result        += howMany;
  236.             buffer        += howMany;
  237.             maxChars    -= howMany;
  238.  
  239.             sr->sr_FIFOReadIndex = (sr->sr_FIFOReadIndex + howMany) % sr->sr_FIFOTotalSize;
  240.         }
  241.         while(maxChars > 0);
  242.  
  243.         /* Subtract the number of characters we
  244.          * read in the loop.
  245.          */
  246.         sr->sr_FIFOBytesStored -= result;
  247.     }
  248.  
  249.     Enable();
  250.  
  251.     return(result);
  252. }
  253.  
  254. STATIC VOID
  255. StoreFIFOChar(struct SashimiResource * sr,UBYTE c)
  256. {
  257.     sr->sr_FIFO[sr->sr_FIFOWriteIndex] = c;
  258.     sr->sr_FIFOWriteIndex = (sr->sr_FIFOWriteIndex + 1) % sr->sr_FIFOTotalSize;
  259.  
  260.     /* If the buffer wraps around, remember it. */
  261.     if(sr->sr_FIFOWriteIndex == 0)
  262.         sr->sr_FIFOWrapped = TRUE;
  263.  
  264.     /* Check if the circular buffer was overrun */
  265.     sr->sr_FIFOBytesStored++;
  266.     if(sr->sr_FIFOBytesStored > sr->sr_FIFOTotalSize)
  267.     {
  268.         sr->sr_FIFOOverrun = TRUE;
  269.  
  270.         /* Move the read index to the same position as
  271.          * the write index and retain only as many
  272.          * bytes as would fit into the FIFO.
  273.          */
  274.         sr->sr_FIFOReadIndex = sr->sr_FIFOWriteIndex;
  275.         sr->sr_FIFOBytesStored = sr->sr_FIFOTotalSize;
  276.     }
  277. }
  278.  
  279. /****************************************************************************/
  280.  
  281. VOID __saveds __asm
  282. NewRawPutChar(register __d0 UBYTE c)
  283. {
  284.     /* Do not store NUL bytes. */
  285.     if(c != '\0')
  286.     {
  287.         STATIC ULONG Position = 0;
  288.  
  289.         Disable();
  290.  
  291.         /* Filter out extra <cr> characters. */
  292.         if(c != '\r' || Position > 0)
  293.         {
  294.             struct SashimiResource * sr = GlobalSashimiResource;
  295.  
  296.             /* Store another byte in the buffer */
  297.             StoreFIFOChar(sr,c);
  298.  
  299.             /* Notify Sashimi every time there is an end of line
  300.              * character in the stream.
  301.              */
  302.             if(c == '\n' || c == '\r')
  303.                 Signal(sr->sr_Owner,sr->sr_OwnerSigMask);
  304.         }
  305.  
  306.         if(c == '\r' || c == '\n')
  307.             Position = 0;
  308.         else
  309.             Position++;
  310.  
  311.         Enable();
  312.     }
  313. }
  314.  
  315. /****************************************************************************/
  316.  
  317. /* This is in SafeRawPutChar.asm */
  318. extern VOID __asm SafeRawPutChar(register __d0 UBYTE c);
  319.  
  320. STATIC VOID
  321. RemovePatches(VOID)
  322. {
  323.     APTR res;
  324.  
  325.     /* We disable the interrupts because the raw I/O routines can
  326.      * be called from within interrupt code.
  327.      */
  328.     Disable();
  329.  
  330.     /* For every patch planted, remove it and check whether the code
  331.      * had been patched before. If it has, restore the patch. Note that
  332.      * this is not bullet proof :(
  333.      */
  334.     res = SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())OldRawIOInit);
  335.     if(res != (APTR)NewRawIOInit)
  336.         SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())res);
  337.  
  338.     res = SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())OldRawMayGetChar);
  339.     if(res != (APTR)NewRawMayGetChar)
  340.         SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())res);
  341.  
  342.     res = SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())OldRawPutChar);
  343.     if(res != (APTR)SafeRawPutChar)
  344.         SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())res);
  345.  
  346.     Enable();
  347. }
  348.  
  349. STATIC VOID
  350. InstallPatches(VOID)
  351. {
  352.     /* We disable the interrupts because the raw I/O routines can
  353.      * be called from within interrupt code.
  354.      */
  355.     Disable();
  356.  
  357.     OldRawIOInit        = SetFunction(SysBase,(LONG)&LVORawIOInit,        (ULONG (*)())NewRawIOInit);
  358.     OldRawMayGetChar    = SetFunction(SysBase,(LONG)&LVORawMayGetChar,    (ULONG (*)())NewRawMayGetChar);
  359.     OldRawPutChar        = SetFunction(SysBase,(LONG)&LVORawPutChar,        (ULONG (*)())SafeRawPutChar);
  360.  
  361.     Enable();
  362. }
  363.  
  364. /****************************************************************************/
  365.  
  366. STATIC VOID
  367. FreeSashimiResource(struct SashimiResource * sr)
  368. {
  369.     if(sr != NULL)
  370.     {
  371.         FreeSignal(sr->sr_OwnerSigBit);
  372.  
  373.         /* Destroy the markers */
  374.         sr->sr_Cookie            = 0;
  375.         sr->sr_PointsToCookie    = NULL;
  376.  
  377.         FreeMem(sr,sizeof(*sr) + sr->sr_FIFOTotalSize-1);
  378.     }
  379. }
  380.  
  381. STATIC LONG
  382. RemoveSashimiResource(struct SashimiResource * sr)
  383. {
  384.     LONG error = OK;
  385.  
  386.     if(sr != NULL)
  387.     {
  388.         Forbid();
  389.  
  390.         /* Allow the resource to be removed only if
  391.          * there are no customers using it.
  392.          */
  393.         if(sr->sr_Library.lib_OpenCnt == 0)
  394.             RemResource(sr);
  395.         else
  396.             error = ERROR_OBJECT_IN_USE;
  397.  
  398.         Permit();
  399.     }
  400.  
  401.     return(error);
  402. }
  403.  
  404. STATIC LONG
  405. AddSashimiResource(ULONG bufferSize,struct SashimiResource ** resourcePtr)
  406. {
  407.     struct SashimiResource * sr;
  408.     LONG error = OK;
  409.  
  410.     /* We will do something really tricky; to increase our chances of
  411.      * allocating an old Sashimi buffer to be recovered, we allocate
  412.      * the amount of memory needed plus the size of a memory chunk.
  413.      * Then we release that buffer again and reallocate it with the
  414.      * size of the memory chunk trailing behind it.
  415.      */
  416.  
  417.     Forbid();
  418.  
  419.     sr = AllocMem(sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1,MEMF_ANY|MEMF_PUBLIC);
  420.     if(sr != NULL)
  421.     {
  422.         FreeMem(sr,sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1);
  423.         sr = AllocAbs(sizeof(*sr) + bufferSize-1,(BYTE *)sr + sizeof(struct MemChunk));
  424.     }
  425.  
  426.     Permit();
  427.  
  428.     if(sr != NULL)
  429.     {
  430.         struct timeval now;
  431.  
  432.         GetSysTime(&now);
  433.  
  434.         memset(sr,0,sizeof(*sr)-1);
  435.  
  436.         sr->sr_Library.lib_Node.ln_Name    = (char *)SashimiResourceName;
  437.         sr->sr_Library.lib_Node.ln_Type    = NT_RESOURCE;
  438.         sr->sr_Owner                    = FindTask(NULL);
  439.         sr->sr_FIFOTotalSize            = bufferSize;
  440.         sr->sr_Cookie                    = COOKIE;
  441.         sr->sr_PointsToCookie            = &sr->sr_Cookie;
  442.         sr->sr_CreatedWhen                = now.tv_secs;
  443.  
  444.         sr->sr_OwnerSigBit = AllocSignal(-1);
  445.         if(sr->sr_OwnerSigBit != -1)
  446.         {
  447.             sr->sr_OwnerSigMask = (1UL << sr->sr_OwnerSigBit);
  448.  
  449.             Forbid();
  450.  
  451.             /* Do not add the resource if it has already been installed. */
  452.             if(OpenResource((STRPTR)SashimiResourceName) == NULL)
  453.                 AddResource(sr);
  454.             else
  455.                 error = ERROR_OBJECT_EXISTS;
  456.  
  457.             Permit();
  458.         }
  459.         else
  460.         {
  461.             error = ERROR_NO_FREE_STORE;
  462.         }
  463.     }
  464.     else
  465.     {
  466.         error = ERROR_NO_FREE_STORE;
  467.     }
  468.  
  469.     if(error != OK)
  470.     {
  471.         FreeSashimiResource(sr);
  472.         sr = NULL;
  473.     }
  474.  
  475.     (*resourcePtr) = sr;
  476.  
  477.     return(error);
  478. }
  479.  
  480. /****************************************************************************/
  481.  
  482. STATIC VOID
  483. CloseSashimiResource(struct SashimiResource * sr)
  484. {
  485.     if(sr != NULL)
  486.     {
  487.         Forbid();
  488.  
  489.         sr->sr_Library.lib_OpenCnt--;
  490.  
  491.         Permit();
  492.     }
  493. }
  494.  
  495. STATIC struct SashimiResource *
  496. OpenSashimiResource(VOID)
  497. {
  498.     struct SashimiResource * sr;
  499.  
  500.     Forbid();
  501.  
  502.     sr = OpenResource((STRPTR)SashimiResourceName);
  503.     if(sr != NULL)
  504.         sr->sr_Library.lib_OpenCnt++;
  505.  
  506.     Permit();
  507.  
  508.     return(sr);
  509. }
  510.  
  511. /****************************************************************************/
  512.  
  513. STATIC LONG
  514. SaveBuffer(const STRPTR name,struct SashimiResource * sr,LONG mode)
  515. {
  516.     LONG error = OK;
  517.     STRPTR buffer;
  518.  
  519.     /* We allocate a temporary buffer to store the circular
  520.      * buffer data in.
  521.      */
  522.     buffer = AllocVec(sr->sr_FIFOTotalSize,MEMF_ANY|MEMF_PUBLIC);
  523.     if(buffer != NULL)
  524.     {
  525.         LONG bytesInBuffer;
  526.         BOOL wrapped;
  527.         BOOL overrun;
  528.         BPTR file;
  529.  
  530.         if(mode == MODE_Regular)
  531.         {
  532.             /* Stop interrupts and multitasking for a tick. */
  533.             Disable();
  534.         }
  535.  
  536.         wrapped = sr->sr_FIFOWrapped;
  537.         overrun = sr->sr_FIFOOverrun;
  538.  
  539.         if(wrapped)
  540.         {
  541.             LONG oldBytes = sr->sr_FIFOTotalSize - sr->sr_FIFOWriteIndex;
  542.  
  543.             /* Unwrap the buffer; first copy the old data (following the
  544.              * write index) then the newer data.
  545.              */
  546.             memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOWriteIndex],oldBytes);
  547.             memcpy(&buffer[oldBytes],sr->sr_FIFO,sr->sr_FIFOWriteIndex);
  548.  
  549.             bytesInBuffer = sr->sr_FIFOTotalSize;
  550.         }
  551.         else
  552.         {
  553.             memcpy(buffer,sr->sr_FIFO,sr->sr_FIFOWriteIndex);
  554.  
  555.             bytesInBuffer = sr->sr_FIFOWriteIndex;
  556.         }
  557.  
  558.         if(mode == MODE_Regular)
  559.         {
  560.             /* Start interrupts and multitasking again. */
  561.             Enable();
  562.         }
  563.  
  564.         /* Write the buffer contents. */
  565.         file = Open((STRPTR)name,MODE_NEWFILE);
  566.         if(file != ZERO)
  567.         {
  568.             if(mode == MODE_Recovery)
  569.             {
  570.                 if(FPrintf(file,"RECOVERY WARNING - Data may have been damaged\n") < 0)
  571.                     error = IoErr();
  572.             }
  573.  
  574.             if(error == OK && overrun)
  575.             {
  576.                 if(FPrintf(file,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
  577.                     error = IoErr();
  578.             }
  579.  
  580.             if(error == OK && wrapped)
  581.             {
  582.                 if(FPrintf(file,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
  583.                     error = IoErr();
  584.             }
  585.  
  586.             /* FPrintf() is a buffered I/O routine, this is why we need to flush the
  587.              * output buffer here. Otherwise, it would be flushed after the Write()
  588.              * command below is finished and the file is closed. This is not what
  589.              * we want as that would have the effect of adding the messages above
  590.              * to the end of the file.
  591.              */
  592.             if(error == OK)
  593.                 Flush(file);
  594.  
  595.             if(error == OK)
  596.             {
  597.                 if(Write(file,buffer,bytesInBuffer) != bytesInBuffer)
  598.                     error = IoErr();
  599.             }
  600.  
  601.             Close(file);
  602.         }
  603.         else
  604.         {
  605.             error = IoErr();
  606.         }
  607.  
  608.         FreeVec(buffer);
  609.     }
  610.     else
  611.     {
  612.         error = ERROR_NO_FREE_STORE;
  613.     }
  614.  
  615.     return(error);
  616. }
  617.  
  618. /****************************************************************************/
  619.  
  620. STATIC BOOL
  621. Recover(const STRPTR fileName)
  622. {
  623.     struct SashimiResource * sr = NULL;
  624.     APTR allocated = NULL;
  625.     struct MemHeader * mh;
  626.     ULONG * start;
  627.     ULONG * end;
  628.     BOOL success;
  629.  
  630.     Printf("Trying to recover old Sashimi buffer... ");
  631.     Flush(Output());
  632.  
  633.     Forbid();
  634.  
  635.     /* Scan the system memory list. */
  636.     for(mh = (struct MemHeader *)((struct ExecBase *)SysBase)->MemList.lh_Head ;
  637.         mh->mh_Node.ln_Succ != NULL ;
  638.         mh = (struct MemHeader *)mh->mh_Node.ln_Succ)
  639.     {
  640.         start    = (ULONG *)mh->mh_Lower;
  641.         end        = (ULONG *)mh->mh_Upper;
  642.  
  643.         do
  644.         {
  645.             /* First look for the cookie... */
  646.             if(start[0] == COOKIE)
  647.             {
  648.                 /* Then look for the pointer back to it. */
  649.                 if(start[1] == (ULONG)start)
  650.                 {
  651.                     /* Unless we don't have a resource pointer
  652.                      * yet, compare the creation times and take
  653.                      * only the latest buffer.
  654.                      */
  655.                     if(sr == NULL || start[2] > sr->sr_CreatedWhen)
  656.                         sr = (struct SashimiResource *)((ULONG)start - offsetof(struct SashimiResource,sr_Cookie));
  657.                 }
  658.             }
  659.         }
  660.         while(++start != end);
  661.     }
  662.  
  663.     /* Try to allocate the memory the old buffer occupies. */
  664.     if(sr != NULL)
  665.         allocated = AllocAbs(sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk),(BYTE *)sr - sizeof(struct MemChunk));
  666.  
  667.     Permit();
  668.  
  669.     if(sr != NULL)
  670.     {
  671.         LONG error = OK;
  672.         LONG numBytes;
  673.  
  674.         if(sr->sr_FIFOWrapped)
  675.             numBytes = sr->sr_FIFOTotalSize;
  676.         else
  677.             numBytes = sr->sr_FIFOWriteIndex;
  678.  
  679.         Printf("found something (%ld bytes).\n",numBytes);
  680.  
  681.         /* If there is anything worth saving, save it. */
  682.         if(numBytes > 0)
  683.         {
  684.             error = SaveBuffer(fileName,sr,MODE_Recovery);
  685.             if(error == OK)
  686.                 Printf("Recovered Sashimi buffer saved as \"%s\".\n",fileName);
  687.             else
  688.                 PrintFault(error,fileName);
  689.         }
  690.         else
  691.         {
  692.             Printf("This is not worth saving.\n");
  693.         }
  694.  
  695.         /* If everything went fine so far and
  696.          * if we are the owner of the buffer,
  697.          * mark it as invalid.
  698.          */
  699.         if(error == OK && allocated != NULL)
  700.         {
  701.             sr->sr_Cookie            = 0;
  702.             sr->sr_PointsToCookie    = NULL;
  703.         }
  704.  
  705.         success = TRUE;
  706.     }
  707.     else
  708.     {
  709.         Printf("sorry.\n");
  710.  
  711.         success = FALSE;
  712.     }
  713.  
  714.     /* Release the buffer... */
  715.     if(allocated != NULL)
  716.         FreeMem(allocated,sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk));
  717.  
  718.     return(success);
  719. }
  720.  
  721. /****************************************************************************/
  722.  
  723. int
  724. main(int argc,char **argv)
  725. {
  726.     int result = RETURN_FAIL;
  727.  
  728.     /* Kickstart 2.04 and a Shell window are required. */
  729.     if(DOSBase->lib_Version >= 37 && argc > 0)
  730.     {
  731.         struct RDArgs * rdargs;
  732.  
  733.         rdargs = ReadArgs((STRPTR)ShellTemplate,(LONG *)&ShellArguments,NULL);
  734.         if(rdargs != NULL)
  735.         {
  736.             /* Before anything else happens, check if
  737.              * we should recover any old data.
  738.              */
  739.             if(ShellArguments.Recover != NULL)
  740.             {
  741.                 if(Recover(ShellArguments.Recover))
  742.                     result = RETURN_OK;
  743.                 else
  744.                     result = RETURN_WARN;
  745.             }
  746.             else
  747.             {
  748.                 struct SashimiResource * sr = NULL;
  749.                 struct MsgPort * timePort;
  750.                 struct timerequest * timeRequest = NULL;
  751.                 BOOL added = FALSE;
  752.                 BOOL opened = FALSE;
  753.                 LONG error = OK;
  754.                 BPTR oldOutput = ZERO;
  755.                 BPTR newOutput = ZERO;
  756.                 BPTR oldInput = ZERO;
  757.                 BPTR newInput = ZERO;
  758.                 struct MsgPort * oldConsoleTask = NULL;
  759.                 STRPTR saveFile;
  760.  
  761.                 /* Fill in the save file name, we might need it later. */
  762.                 if(ShellArguments.SaveAs != NULL)
  763.                     saveFile = ShellArguments.SaveAs;
  764.                 else
  765.                     saveFile = "T:sashimi.out";
  766.  
  767.                 /* Set up the timer.device interface. */
  768.                 timePort = CreateMsgPort();
  769.                 if(timePort != NULL)
  770.                 {
  771.                     timeRequest = (struct timerequest *)CreateIORequest(timePort,sizeof(*timeRequest));
  772.                     if(timeRequest != NULL)
  773.                     {
  774.                         if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
  775.                             TimerBase = timeRequest->tr_node.io_Device;
  776.                         else
  777.                             error = ERROR_NO_FREE_STORE; /* Misleading? */
  778.                     }
  779.                     else
  780.                     {
  781.                         error = ERROR_NO_FREE_STORE;
  782.                     }
  783.                 }
  784.                 else
  785.                 {
  786.                     error = ERROR_NO_FREE_STORE;
  787.                 }
  788.  
  789.                 if(error == OK)
  790.                 {
  791.                     /* Try to open the resource, and if that fails, create one. */
  792.                     sr = OpenSashimiResource();
  793.                     if(sr != NULL)
  794.                     {
  795.                         opened = TRUE;
  796.                     }
  797.                     else
  798.                     {
  799.                         ULONG bufferSize;
  800.     
  801.                         /* The default buffer size is 32K. */
  802.                         bufferSize = 32 * 1024;
  803.     
  804.                         /* Check for a specific buffer size (power of two). */
  805.                         if(ShellArguments.BufferK != NULL)
  806.                             bufferSize = 1024 * (*ShellArguments.BufferK);
  807.     
  808.                         /* Check for a specific buffer size. */
  809.                         if(ShellArguments.BufferSize != NULL)
  810.                             bufferSize = (ULONG)(*ShellArguments.BufferSize);
  811.     
  812.                         /* Don't make the buffer too small. */
  813.                         if(bufferSize < 4096)
  814.                             bufferSize = 4096;
  815.     
  816.                         /* Add the resource to the public list. Note that
  817.                          * the patches are not installed yet.
  818.                          */
  819.                         error = AddSashimiResource(bufferSize,&sr);
  820.                         if(error == OK)
  821.                             added = TRUE;
  822.                     }
  823.                 }
  824.  
  825.                 /* Did we get everything we wanted? */
  826.                 if(error != OK)
  827.                 {
  828.                     PrintFault(error,"Sashimi");
  829.                     result = RETURN_ERROR;
  830.                 }
  831.                 else
  832.                 {
  833.                     if(opened)
  834.                     {
  835.                         /* Save the current circular buffer contents? */
  836.                         if(ShellArguments.SaveAs != NULL || ShellArguments.Save)
  837.                         {
  838.                             LONG error;
  839.  
  840.                             error = SaveBuffer(saveFile,sr,MODE_Regular);
  841.                             if(error == OK)
  842.                                 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  843.                             else
  844.                                 PrintFault(error,saveFile);
  845.                         }
  846.  
  847.                         /* Empty the circular buffer? */
  848.                         if(ShellArguments.Empty)
  849.                         {
  850.                             EmptyFIFO(sr);
  851.  
  852.                             Printf("Sashimi buffer cleared.\n");
  853.                         }
  854.  
  855.                         /* Turn off Sashimi? */
  856.                         if(ShellArguments.Off)
  857.                         {
  858.                             struct Task * owner;
  859.  
  860.                             Forbid();
  861.  
  862.                             /* We cannot tell Sashimi to quit
  863.                              * if there is a single customer
  864.                              * left, such as us. This is why
  865.                              * we close the resource and
  866.                              * signal Sashimi to quit.
  867.                              */
  868.                             owner = sr->sr_Owner;
  869.                             CloseSashimiResource(sr);
  870.                             sr = NULL;
  871.  
  872.                             Signal(owner,SIGBREAKF_CTRL_C);
  873.  
  874.                             Permit();
  875.                         }
  876.                     }
  877.  
  878.                     if(added && NOT ShellArguments.Off)
  879.                     {
  880.                         ULONG signalsReceived,signalsToWaitFor;
  881.                         BOOL done;
  882.  
  883.                         /* Open a console window? */
  884.                         if(ShellArguments.Console)
  885.                         {
  886.                             STRPTR consoleWindow;
  887.                             LONG error = OK;
  888.  
  889.                             if(ShellArguments.Window != NULL)
  890.                                 consoleWindow = ShellArguments.Window;
  891.                             else
  892.                                 consoleWindow = "CON:0/20/640/100/Sashimi  [Ctrl]+E=Empty  [Ctrl]+F=File  [Ctrl]+D=Reset console/AUTO/CLOSE/WAIT/INACTIVE";
  893.  
  894.                             /* Open the window and make it the default
  895.                              * I/O stream.
  896.                              */
  897.                             newInput = Open(consoleWindow,MODE_NEWFILE);
  898.                             if(newInput != ZERO)
  899.                             {
  900.                                 oldConsoleTask = SetConsoleTask(((struct FileHandle *)BADDR(newInput))->fh_Type);
  901.                                 newOutput = Open("CONSOLE:",MODE_OLDFILE);
  902.                                 if(newOutput != ZERO)
  903.                                 {
  904.                                     oldInput = SelectInput(newInput);
  905.                                     oldOutput = SelectOutput(newOutput);
  906.                                 }
  907.                                 else
  908.                                 {
  909.                                     error = IoErr();
  910.  
  911.                                     /* Return to the original console task. */
  912.                                     SetConsoleTask(oldConsoleTask);
  913.                                     oldConsoleTask = NULL;
  914.                                 }
  915.                             }
  916.                             else
  917.                             {
  918.                                 error = IoErr();
  919.                             }
  920.  
  921.                             if(error != OK)
  922.                                 PrintFault(error,consoleWindow);
  923.                         }
  924.  
  925.                         /* Show the banner message. */
  926.                         if(NOT ShellArguments.NoPrompt && NOT ShellArguments.Quiet)
  927.                         {
  928.                             struct Process * cli = (struct Process *)FindTask(NULL);
  929.                             LONG maxCli,thisCli = 1,i;
  930.  
  931.                             /* Find our current CLI process number. */
  932.                             maxCli = MaxCli();
  933.                             for(i = 1 ; i <= maxCli ; i++)
  934.                             {
  935.                                 if(FindCliProc(i) == cli)
  936.                                 {
  937.                                     thisCli = i;
  938.                                     break;
  939.                                 }
  940.                             }
  941.  
  942.                             Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli);
  943.                         }
  944.  
  945.                         GlobalSashimiResource = sr;
  946.                         InstallPatches();
  947.  
  948.                         signalsToWaitFor = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
  949.                                            SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F |
  950.                                            sr->sr_OwnerSigMask;
  951.  
  952.                         /* Start the timer. */
  953.                         if(ShellArguments.TimerOn)
  954.                         {
  955.                             signalsToWaitFor |= (1UL << timePort->mp_SigBit);
  956.  
  957.                             timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  958.                             timeRequest->tr_time.tv_secs    = 0;
  959.                             timeRequest->tr_time.tv_micro    = MILLION / 10;
  960.  
  961.                             SendIO((struct IORequest *)timeRequest);
  962.                         }
  963.  
  964.                         done = FALSE;
  965.                         do
  966.                         {
  967.                             signalsReceived = Wait(signalsToWaitFor);
  968.  
  969.                             /* Check if we should test the buffer. */
  970.                             if(ShellArguments.TimerOn)
  971.                             {
  972.                                 if(signalsReceived & (1UL << timePort->mp_SigBit))
  973.                                 {
  974.                                     signalsReceived |= sr->sr_OwnerSigMask;
  975.  
  976.                                     WaitIO((struct IORequest *)timeRequest);
  977.  
  978.                                     /* Restart the timer. */
  979.                                     timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  980.                                     timeRequest->tr_time.tv_secs    = 0;
  981.                                     timeRequest->tr_time.tv_micro    = MILLION / 10;
  982.  
  983.                                     SendIO((struct IORequest *)timeRequest);
  984.                                 }
  985.                             }
  986.  
  987.                             /* Check if we should test the buffer. */
  988.                             if(signalsReceived & sr->sr_OwnerSigMask)
  989.                             {
  990.                                 if(NOT ShellArguments.Quiet)
  991.                                 {
  992.                                     UBYTE localBuffer[256];
  993.                                     ULONG moreSignals;
  994.                                     LONG filled;
  995.  
  996.                                     /* Try to empty the circular buffer. */
  997.                                     while((filled = ReadFIFOChars(sr,localBuffer,sizeof(localBuffer))) > 0)
  998.                                     {
  999.                                         /* Check if there is a message for us. */
  1000.                                         moreSignals = SetSignal(0,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
  1001.  
  1002.                                         /* Save the circular buffer to a file? */
  1003.                                         if(moreSignals & SIGBREAKF_CTRL_F)
  1004.                                         {
  1005.                                             LONG error;
  1006.  
  1007.                                             error = SaveBuffer(saveFile,sr,MODE_Regular);
  1008.                                             if(error == OK)
  1009.                                                 Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  1010.                                             else
  1011.                                                 PrintFault(error,saveFile);
  1012.                                         }
  1013.  
  1014.                                         /* Empty the circular buffer? */
  1015.                                         if(moreSignals & SIGBREAKF_CTRL_E)
  1016.                                         {
  1017.                                             EmptyFIFO(sr);
  1018.  
  1019.                                             Printf("Sashimi buffer cleared.\n");
  1020.                                             filled = 0;
  1021.                                         }
  1022.  
  1023.                                         /* Stop Sashimi? */
  1024.                                         if(moreSignals & SIGBREAKF_CTRL_C)
  1025.                                         {
  1026.                                             signalsReceived |= SIGBREAKF_CTRL_C;
  1027.                                             break;
  1028.                                         }
  1029.  
  1030.                                         /* Write the buffer to the file. */
  1031.                                         if(filled > 0)
  1032.                                             Write(Output(),localBuffer,filled);
  1033.                                     }
  1034.                                 }
  1035.                             }
  1036.  
  1037.                             /* Save current buffer to file. */
  1038.                             if(signalsReceived & SIGBREAKF_CTRL_F)
  1039.                             {
  1040.                                 LONG error;
  1041.  
  1042.                                 error = SaveBuffer(saveFile,sr,MODE_Regular);
  1043.                                 if(error == OK)
  1044.                                     Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
  1045.                                 else
  1046.                                     PrintFault(error,saveFile);
  1047.                             }
  1048.  
  1049.                             /* Empty the buffer. */
  1050.                             if(signalsReceived & SIGBREAKF_CTRL_E)
  1051.                             {
  1052.                                 EmptyFIFO(sr);
  1053.  
  1054.                                 Printf("Sashimi buffer cleared.\n");
  1055.                             }
  1056.  
  1057.                             /* Reset the terminal. */
  1058.                             if(signalsReceived & SIGBREAKF_CTRL_D)
  1059.                             {
  1060.                                 Printf("\033c");
  1061.                                 Flush(Output());
  1062.                             }
  1063.  
  1064.                             /* Terminate the program. */
  1065.                             if(signalsReceived & SIGBREAKF_CTRL_C)
  1066.                             {
  1067.                                 BOOL terminate = FALSE;
  1068.  
  1069.                                 if(ShellArguments.AskExit)
  1070.                                 {
  1071.                                     UBYTE buffer[4];
  1072.  
  1073.                                     Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
  1074.                                     Flush(Output());
  1075.  
  1076.                                     buffer[0] = '\0';
  1077.  
  1078.                                     if(FGets(Input(),buffer,sizeof(buffer)-1) != NULL)
  1079.                                     {
  1080.                                         if(buffer[0] == 'y' || buffer[0] == 'Y')
  1081.                                             terminate = TRUE;
  1082.                                     }
  1083.                                 }
  1084.                                 else
  1085.                                 {
  1086.                                     terminate = TRUE;
  1087.                                 }
  1088.  
  1089.                                 if(terminate)
  1090.                                 {
  1091.                                     if(RemoveSashimiResource(sr) == OK)
  1092.                                     {
  1093.                                         Printf("Sashimi removed.\n");
  1094.                                         done = TRUE;
  1095.                                     }
  1096.                                 }
  1097.                             }
  1098.                         }
  1099.                         while(NOT done);
  1100.  
  1101.                         RemovePatches();
  1102.  
  1103.                         /* Stop the timer. */
  1104.                         if(ShellArguments.TimerOn)
  1105.                         {
  1106.                             if(CheckIO((struct IORequest *)timeRequest) == BUSY)
  1107.                                 AbortIO((struct IORequest *)timeRequest);
  1108.  
  1109.                             WaitIO((struct IORequest *)timeRequest);
  1110.                         }
  1111.  
  1112.                         /* Check if we should and could save the circular buffer. */
  1113.                         if(ShellArguments.AskSave && GetCharsInFIFO(sr) > 0)
  1114.                         {
  1115.                             UBYTE name[256];
  1116.  
  1117.                             Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
  1118.                             Flush(Output());
  1119.  
  1120.                             name[0] = '\0';
  1121.  
  1122.                             if(FGets(Input(),name,sizeof(name)-1) != NULL)
  1123.                             {
  1124.                                 LONG error;
  1125.                                 int i;
  1126.  
  1127.                                 for(i = strlen(name)-1 ; i >= 0 ; i--)
  1128.                                 {
  1129.                                     if(name[i] == '\n')
  1130.                                         name[i] = '\0';
  1131.                                 }
  1132.  
  1133.                                 error = SaveBuffer(name,sr,MODE_Regular);
  1134.                                 if(error == OK)
  1135.                                     Printf("Sashimi buffer saved as \"%s\".\n",name);
  1136.                                 else
  1137.                                     PrintFault(error,name);
  1138.                             }
  1139.                         }
  1140.  
  1141.                         FreeSashimiResource(sr);
  1142.                         sr = NULL;
  1143.                     }
  1144.  
  1145.                     result = RETURN_OK;
  1146.                 }
  1147.  
  1148.                 /* Close the resource, if we opened it. */
  1149.                 if(opened)
  1150.                     CloseSashimiResource(sr);
  1151.  
  1152.                 /* Remove and free the resource if we added it. */
  1153.                 if(added)
  1154.                 {
  1155.                     RemoveSashimiResource(sr);
  1156.                     FreeSashimiResource(sr);
  1157.                 }
  1158.  
  1159.                 /* Clean up the timer.device interface. */
  1160.                 if(timeRequest != NULL)
  1161.                 {
  1162.                     if(timeRequest->tr_node.io_Device != NULL)
  1163.                         CloseDevice((struct IORequest *)timeRequest);
  1164.  
  1165.                     DeleteIORequest((struct IORequest *)timeRequest);
  1166.                 }
  1167.  
  1168.                 DeleteMsgPort(timePort);
  1169.  
  1170.                 /* Reset and clean up the console I/O streams. */
  1171.                 if(oldOutput != ZERO)
  1172.                     SelectOutput(oldOutput);
  1173.  
  1174.                 if(oldInput != ZERO)
  1175.                     SelectInput(oldInput);
  1176.  
  1177.                 if(newOutput != ZERO)
  1178.                     Close(newOutput);
  1179.  
  1180.                 if(oldConsoleTask != NULL)
  1181.                     SetConsoleTask(oldConsoleTask);
  1182.  
  1183.                 if(newInput != ZERO)
  1184.                     Close(newInput);
  1185.             }
  1186.  
  1187.             FreeArgs(rdargs);
  1188.         }
  1189.         else
  1190.         {
  1191.             PrintFault(IoErr(),"Sashimi");
  1192.  
  1193.             result = RETURN_ERROR;
  1194.         }
  1195.     }
  1196.  
  1197.     return(result);
  1198. }
  1199.